package com.qd.pay.service.order;

import cn.hutool.core.net.NetUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.dto.CacheKey;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.DateUtil;
import com.cdqidi.util.IpHelper;
import com.cdqidi.util.RedisTemplateUtil;
import com.qd.pay.domain.*;
import com.qd.pay.model.Order;
import com.qd.pay.model.OrderBody;
import com.qd.pay.model.OrderRefund;
import com.qd.pay.model.OrderTf;
import com.qd.pay.service.*;
import com.qd.pay.util.IdUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author sjk
 */
@Component
@AllArgsConstructor
@Slf4j
public class OrderHolderService {
    private final RedisTemplateUtil<Order> redisTemplateUtil;
    private final HttpServletRequest httpServletRequest;
    private final WxOrderService wxOrderService;
    private final TfOrderService tfOrderService;
    private final OrderTfService orderTfService;
    private final OrderService orderService;
    private final OrderExtendedService orderExtendedService;

    private final OrderBodyService orderBodyService;
    private final OrderRefundService orderRefundService;
    private final OrderReportService orderReportService;
    private final OrderRefundReportService orderRefundReportService;

    /**
     * 创建订单
     *
     * @param dto 订单参数
     * @return 支付参数
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> createOrder(OrderDTO dto) {
        Map<String, String> map;
        final LocalDateTime sendTime = LocalDateTime.now();
        String thirdPartyOrder = dto.getThirdPartyOrder();
        Order order = orderService.getByThirdPartyOrder(thirdPartyOrder);
        if (null != order) {
            throw new ApiException(3, "订单已经存在，请勿重复提交");
        }
        String orderId = IdWorker.getIdStr();
        String outTradeNo = IdUtil.getOutTradeNo();
        order = new Order();
        if (null != dto.getType()) {
            order.setType(dto.getType());
        }
        order.setSubject(dto.getSubject());
        order.setApCode(dto.getApCode());
        order.setBody(dto.getBody());
        order.setIpAddress(IpHelper.getIpAddress(httpServletRequest));
        order.setNotifyUrl(dto.getNotifyUrl());
        order.setOrderId(orderId);
        order.setOutTradeNo(outTradeNo);
        order.setPayAmount(dto.getPayAmount());
        order.setSendTime(sendTime);
        order.setPersonid(dto.getPersonId());
        order.setThirdPartyOrder(thirdPartyOrder);
        order.setState(0);
        OrderBody body = new OrderBody().setBid(orderId).setType(OrderBodyDTO.ORDER_TYPE_ORDER).setAddTime(sendTime);
        if (order.getType() == 0) {
            map = wxOrderService.createWxOrder(dto, order, body);
        } else if (order.getType() == 2 || order.getType() == 3) {
            map = tfOrderService.createOrder(dto, order, body);
        } else {
            log.error("类型错误,type: {}", order.getType());
            throw new ApiException("类型错误");
        }
        orderService.save(order);
        orderBodyService.save(body);
        if (null != dto.getAttach()) {
            //保存附加参数
            OrderExtendedDTO orderExtended = new OrderExtendedDTO();
            orderExtended.setOrderId(orderId);
            orderExtended.setAttach(dto.getAttach().toString());
            orderExtendedService.save(orderExtended);
            orderExtended.freeData();
        }
        String key = RedisTemplateUtil.getRedisCacheKey(OrderService.PREFIX_ID, orderId);
        redisTemplateUtil.set(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY * 3), order);
        key = RedisTemplateUtil.getRedisCacheKey(OrderService.PREFIX_OUT_TRADE_NO, outTradeNo);
        redisTemplateUtil.set(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY * 3), order);
        key = RedisTemplateUtil.getRedisCacheKey(OrderService.PREFIX_THIRD_PARTY_ORDER, order.getThirdPartyOrder());
        redisTemplateUtil.set(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY * 3), order);
        order.freeData();
        body.freeData();
        return map;
    }

    /**
     * 关闭订单
     *
     * @param closeOrderDTO 参数
     */
    @Transactional(rollbackFor = Exception.class)
    public ApiResultWrapper<Object> closeOrder(CloseOrderDTO closeOrderDTO) {
        String orderId = closeOrderDTO.getOrderId();
        String thirdPartyOrderId = closeOrderDTO.getThirdPartyOrderId();
        Integer type = closeOrderDTO.getType();
        if (!StringUtils.hasLength(orderId) && !StringUtils.hasLength(thirdPartyOrderId)) {
            return ApiResult.error("订单ID不能为空");
        }
        Order order = null;
        if (StringUtils.hasLength(orderId)) {
            order = orderService.getById(orderId);
        }
        if (null == order) {
            if (StringUtils.hasLength(thirdPartyOrderId)) {
                order = orderService.getByThirdPartyOrder(orderId);
            }
        }
        if (null == order) {
            return ApiResult.error("订单不存在，不能关闭订单");
        }
        if (order.getState() == 1) {
            return ApiResult.error("订单已经关闭，请勿重复操作");
        }
        if (type == 0) {
            //关闭微信订单
            wxOrderService.closeWxOrder(closeOrderDTO.getAppId(), order);
        } else if (type == 2) {
            //关闭天府银行订单
            tfOrderService.closeWxOrder(order);
        } else {
            return ApiResult.error("类型错误");
        }

        return ApiResult.success();
    }

    /**
     * 退款
     *
     * @param dto 参数
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public ApiResultWrapper<Object> orderRefund(OrderRefundDTO dto) {
        if (null == dto.getRefundNo() || 0 == dto.getRefundNo()) {
            dto.setRefundNo(1);
        }
        Order order = null;
        if (StringUtils.hasLength(dto.getOrderId())) {
            order = orderService.getById(dto.getOrderId());
        }
        if (null == order) {
            if (StringUtils.hasLength(dto.getThirdPartyOrder())) {
                order = orderService.getByThirdPartyOrder(dto.getThirdPartyOrder());
            }
        }
        if (null == order) {
            return ApiResult.error("订单不存在，不能完成退款");
        }
        if (order.getState() == 1) {
            return ApiResult.error("订单已经关闭不能退款");
        }
        long days = DateUtil.timeDifference(order.getSendTime().toLocalDate());
        if (days > 364) {
            return ApiResult.error("订单超过一年不能退款");
        }
        boolean exists = orderRefundService.isExistsByOrderIdAndRefundNo(order.getOrderId(), dto.getRefundNo());
        if (exists) {
            log.info("当前订单已经申请过退款，请勿重复提交,orderId: {},refundNo: {}", order.getOrderId(), dto.getRefundNo());
            return ApiResult.error("当前订单已经申请过退款，请勿重复提交");
        }
        exists = orderReportService.exists(order.getOrderId(), OrderService.SUCCESS);
        if (!exists) {
            if (dto.getType() == 0) {
                Map<String, Object> map = wxOrderService.getOrderReport(order, dto.getAppId());
                Object orderState = map.get("orderState");
                if (!orderState.equals(OrderService.SUCCESS)) {
                    throw new ApiException("当前订单支付状态为： " + map.get("orderStateMsg") + "，不能完成退款");
                }
            } else if (dto.getType() == 2) {

            } else {
                throw new ApiException("订单类型错误");
            }

        }
        /*
            是否有过退款申请，如果有查询退款总金额
         */
        boolean b = orderRefundService.isExistsByOrderId(order.getOrderId());
        if (b) {
            /*
             * 先在自己的数据库中验证成功退款的金额
             */
            Integer refundTotal = orderRefundReportService.refundTotal(order.getOrderId(), OrderService.SUCCESS);
            if (null != refundTotal) {
                if (new BigDecimal(refundTotal).compareTo(order.getPayAmount()) >= BigInteger.ZERO.signum()) {
                    throw new ApiException("退款总金额超过当前订单支付金额，不能退款");
                }
            }
            if (dto.getType() == 0) {
                /*
                 *当前订单已经发起过退款，此时需要到微信端验证当前订单是否已经退款，退款的总金额是好多，如果已经达到当前订单的金额
                 * 那么不能继续退款
                 */
                wxOrderService.checkRefund(order, dto);
            } else if (dto.getType() == 2) {
                //目前不处理
            }
        }
        String rid = IdWorker.getIdStr();
        OrderRefund orderRefund = orderRefundService.dtoToModel(dto);
        orderRefund.setRid(rid);
        orderRefund.setOrderId(order.getOrderId());
        try {
            orderRefund.setIpAddress(IpHelper.getIpAddress(httpServletRequest));
        } catch (Exception e) {
            final String localhostStr = NetUtil.getLocalhostStr();
            if (StringUtils.hasLength(localhostStr)) {
                orderRefund.setIpAddress(localhostStr);
            }
        }
        orderRefund.setSendTime(LocalDateTime.now());
        orderRefund.setPayAmount(order.getPayAmount());

        OrderBody orderBody = new OrderBody().setBid(rid).setType(OrderBodyDTO.ORDER_TYPE_ORDER_REFUND).setAddTime(orderRefund.getSendTime());
        if (dto.getType() == 0) {
            wxOrderService.orderRefund(dto, order, orderRefund, orderBody);
        } else if (dto.getType() == 2) {
            tfOrderService.orderRefund(dto, order, orderRefund, orderBody);
        }


        orderRefundService.save(orderRefund);
        orderRefund.freeData();

        orderBodyService.save(orderBody);
        orderBody.freeData();

        dto.freeData();

        return ApiResult.success("退款成功");
    }


    /**
     * 查询订单状态
     *
     * @param orderId    订单ID
     * @param selectType 类型
     * @param type       订单类型0微信1支付宝2天府银行
     * @return
     */
    @Transactional(readOnly = true)
    public ApiResultWrapper<Object> orderState(String orderId, String selectType, String appId, Integer type) {
        boolean isOrderResp = false;
        boolean isOrderReport = false;
        boolean isOrderRefund = false;
        if (StringUtils.hasLength(selectType)) {
            String[] split = selectType.split(";");
            for (String s : split) {
                if ("orderResp".equals(s)) {
                    isOrderResp = true;
                }
                if ("orderReport".equals(s)) {
                    isOrderReport = true;
                }
                if ("orderRefund".equals(s)) {
                    isOrderRefund = true;
                }
            }
        } else {
            isOrderResp = true;
            isOrderReport = true;
            isOrderRefund = true;
        }
        Order order = orderService.getById(orderId);
        if (null == order) {
            order = orderService.getByThirdPartyOrder(orderId);
        }
        if (null == order) {
            return ApiResult.error("订单不存在");
        }
        Map<String, Object> map = new LinkedHashMap<>(4);
        if (type == 0) {
            wxOrderService.wxOrderState(appId, isOrderResp, isOrderReport, isOrderRefund, order, map);
        } else if (type == 2) {
            final OrderTf orderTf = Optional.ofNullable(orderTfService.getById(order.getOrderId())).orElseThrow(() -> new ApiException("天府银行订单不存在"));
            final Map<String, Object> reportMap = tfOrderService.orderState(orderTf.getPartner(), orderTf.getSubPartner(), order.getOutTradeNo());
            map.put("orderReport", reportMap);
            if (isOrderRefund) {
                final List<OrderRefund> refundList = orderRefundService.getListByOrderId(order.getOrderId());
                for (int i = 0; i < refundList.size(); i++) {
                    final OrderRefund orderRefund = refundList.get(i);
                    final Map<String, Object> map1 = tfOrderService.orderState(orderTf.getPartner(), orderTf.getSubPartner(), orderRefund.getOutTradeNo());
                    map.put("orderRefundReport" + i, map1);
                }
            }
        } else {
            throw new ApiException("不支持的订单类型");
        }

        order.freeData();
        return ApiResult.success(map);
    }


}